package uk.ac.aber.Blockmation;

import java.awt.image.BufferedImage;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import java.util.ArrayList;
import uk.ac.aber.Blockmation.GIF.AnimatedGifEncoder;
import uk.ac.aber.Blockmation.GIF.GifDecoder;

/**
 * Provides reading and saving of files TXT and GIF facility from a file to
 * MovieModel object and vice-versa. 
 * @author Aron
 *
 */
public class FileManager
{
	/**
	 * A service static method to deliver file extension.
	 * @param file - to check the extension of
	 * @return extension of the provided file, or "" empty string if the
	 * file hasn't got an extension.
	 */
    public static String getExtFromFile(File file)
    {
    	String ext;
        if (file != null )
        {
    	String filename = file.getName();
        ext = (filename.lastIndexOf(".") == -1) ? ""  
        				: filename.substring(filename.lastIndexOf(".") + 1, 
        				filename.length());
        } else
        {
        	ext = "";
        }

        return ext;
    }

    /**
     * Returns MovieModel object with frames from file that can be specific TXT 
     * or GIF file only.
     * @param file - file to read from
     * @return MovieModel object converted from provided file, null if the file 
     * coulnd't be found or read.
     */
    public static MovieModel loadMovie(File file)
    {
        MovieModel movieModel = new MovieModel();
        String ext;
        
        // make sure file provided exists
        if ((file != null) && file.exists())
        {
            // gets extension and chooses appropriate encoding method
        	ext = FileManager.getExtFromFile(file);

        	// for txt Scotty file type
            if (ext.equalsIgnoreCase("txt"))
            {
                // initialize to null and check exceptions
                ArrayList<BufferedImage> images = new ArrayList<BufferedImage>();
                ScottyIntoImages sii = new ScottyIntoImages();
                
                images = sii.decodeAsBufferedImages(file.getAbsolutePath());
                if (images == null)
                {
                	return null;
                } else
                {
                	for (BufferedImage bim : images)
                	{
                		movieModel.appendFrame(bim);
                	}

                	System.out.println(file +" Scotty file loaded to model.");
                }
            }
            // for animating GIF file type, use third party decoder
            else if (ext.equalsIgnoreCase("gif"))
            {
                GifDecoder gifDecoder = new GifDecoder();
                gifDecoder.read(file.getAbsolutePath());
                
                int frameCount = gifDecoder.getFrameCount();
                int speed = 500; // default speed in milliseconds
                
                // gets separate images from GIF and saves them to MovieModel object
                for (int i = 0; i < frameCount; i++) {
                    
                    BufferedImage frame = gifDecoder.getFrame(i);
                    movieModel.appendFrame(frame);
                    speed = gifDecoder.getDelay(i); 
                    
                }
                // set only one speed, here: the speed between last frames, it's enough
                movieModel.setSpeed(speed);
                
                System.out.println(file + " GIF file loaded to model");
            }   
        }
        else
        {
            System.err.println("Cannot load movie. File doesn't exist");
            return null;
        }

        return movieModel;
    }

    /**
     * Saves MovieModel object to a file. In either TXT or animating GIF
     * file format.
     * @param movieModel - to be saved into the file.
     * @param file - into which you want to save the file, with appropriate 
     * extension of txt or gif.
     * @return file - the file that the MovieModel object has been saved to, null - 
     * when the MovieModel object couldn't been saved for some reason.
     */
    public static File save(MovieModel movieModel, File file)
    {
        if ((file == null))
        {
            System.err.println("No File file provided");
            return null;
        } else if (movieModel == null)
        {
            System.err.println("Model hasn't been initialized. Nothing to save.");
            return null;
        } else
        {
        	// gets extension of the file and chooser appropriate encoding method
            String ext = FileManager.getExtFromFile(file);
            if (ext.equalsIgnoreCase("txt"))
            {
            	/* 
            	 * gets each frame from MovieModel object, stores it in ArrayList of
            	 * BufferedImages and then encodes its using ImagesIntoScotty class.
            	 */
                    ArrayList<BufferedImage> animation = new ArrayList<BufferedImage>();

                    for (int i = 0; i < movieModel.size(); i++)
                    {
                        animation.add(movieModel.get(i));
                    }

                    	ImagesIntoScotty iis = new ImagesIntoScotty();
                        try {
							iis.encode(animation, file);
						} catch (FileNotFoundException e) {
							System.err.println("Cannot find the file to save it. Couldn't save.");
							return null;
						} catch (IOException e) {
							System.err.println("Couldn't save the file.");
							return null;
						}
  
              } 
            // encode to GIF using external class
            	else if (ext.equalsIgnoreCase("gif"))
              {
                AnimatedGifEncoder gifEncoder = new AnimatedGifEncoder();
                gifEncoder.start(file.getAbsolutePath());
                gifEncoder.setDelay(movieModel.getSpeed());
                
                boolean addingOk = true;
                
                for (int i = 0; i < movieModel.size()-1; i++) 
                {
                	// && op used to check whether at least once the result was false
                	addingOk = addingOk && gifEncoder.addFrame(movieModel.get(i));
                }

                if ( !gifEncoder.finish() )
                {
                	System.err.println("I/O Saving problem on GIFEncoder side.");
                	return null;
                }
                if (!addingOk)
                {
                	System.err.println("File saved to GIF but some frames corrupted!");
                }
              } else
              {
            	  System.err.println("No or wrong file extension provided");
            	  file = null;
              }


        return file;
    }
}
}
